﻿using System;
using System.Threading;
using System.Windows.Navigation;
using GurLoader.View;
using NUnit.Framework;

namespace GurLoaderWPF.Test.View
{
    [TestFixture]
    public class RelayCommandTests
    {
        [Test]
        public void CreateInstanceTest()
        {
            var relayCommand = new RelayCommand<object>
            {
                CanExecuteFunc = e => { return false; },
                CommandAction = obj => { }
            };

            Assert.IsNotNull(relayCommand);
        }

        [Test]
        public void CanExecuteNonNullTest()
        {
            var relayCommand = new RelayCommand<object>
            {
                CanExecuteFunc = e => { return true; },
                CommandAction = obj => { }
            };

            Assert.IsNotNull(relayCommand);
            Assert.IsTrue(relayCommand.CanExecute(new object()));
        }

        [Test]
        public void CanExecuteNullTest()
        {
            var relayCommand = new RelayCommand<object>
            {
                CanExecuteFunc = null,
                CommandAction = obj => { }
            };

            Assert.IsNotNull(relayCommand);
            Assert.IsTrue(relayCommand.CanExecute(new object()));
        }

        [Test]
        public void ExecuteNonNullTest()
        {
            var mre = new ManualResetEvent(false);

            var relayCommand = new RelayCommand<object>
            {
                CanExecuteFunc = e => { return false; },
                CommandAction = obj => { mre.Set(); }
            };

            Assert.IsNotNull(relayCommand);

            relayCommand.Execute(new object());
            Assert.IsTrue(mre.WaitOne(1000*5)); // wait 5 seconds max
        }

        private class FakeRequeryable : IRequeryable
        {
            public event EventHandler RequerySuggested;

            public void FireRequerySuggested()
            {
                if (RequerySuggested != null)
                    RequerySuggested(this, EventArgs.Empty);
            }
        }

        [Test]
        public void AddToCanExecuteChangedTest()
        {
            var req = new FakeRequeryable();
            var mre = new ManualResetEvent(false);

            var relayCommand = new RelayCommand<object>(req)
            {
                CanExecuteFunc = e => { return false; },
                CommandAction = obj => { }
            };

            relayCommand.CanExecuteChanged += (obj, e) => { mre.Set(); };

            Assert.IsNotNull(relayCommand);

            req.FireRequerySuggested();

            Assert.IsTrue(mre.WaitOne(1000*5));
        }


        [Test]
        public void RemoveFromCanExecuteChangedTest()
        {
            var req = new FakeRequeryable();
            var mre = new ManualResetEvent(false);

            var relayCommand = new RelayCommand<object>(req)
            {
                CanExecuteFunc = e => { return false; },
                CommandAction = obj => { }
            };

            EventHandler eh = new EventHandler((obj, e) =>
            {
                mre.Set();
            });

            relayCommand.CanExecuteChanged += eh;

            Assert.IsNotNull(relayCommand);

            req.FireRequerySuggested();

            Assert.IsTrue(mre.WaitOne(1000*3));

            mre.Reset();

            relayCommand.CanExecuteChanged -= eh;

            req.FireRequerySuggested();

            Assert.IsFalse(mre.WaitOne(1000*3));

        }
    }
}
